﻿namespace Contoso.ActiveDirectory {

    #region Usings
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.DirectoryServices;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    #endregion

    /// <summary>
    /// A DNS Start Of Authority (SOA) record.
    /// Specifies authoritative information about a DNS zone, including the primary name server, the email of the domain administrator, 
    /// the domain serial number, and several timers relating to refreshing the zone.
    /// </summary>
    [Serializable]
    public class DNSSOARecord : DNSResourceRecord {

        #region Members
        
        /// <summary>
        /// The expiration of the records in seconds
        /// </summary>
        public uint Expire { get; private set; }

        /// <summary>
        /// The minimum TTL in seconds
        /// </summary>
        public uint MinimumTTL { get; private set; }

        /// <summary>
        /// The refresh interval in seconds
        /// </summary>
        public uint Refresh { get; private set; }

        /// <summary>
        /// The contact person for the record (zone)
        /// </summary>
        public string ResponsiblePerson { get; private set; }

        /// <summary>
        /// The retry interval in seconds
        /// </summary>
        public uint Retry { get; private set; }

        /// <summary>
        /// The serial number of the record
        /// </summary>
        public uint Serial { get; private set; }

        /// <summary>
        /// The target host name
        /// </summary>
        public string TargetName { get; private set; }

        #endregion

        #region Constructor
        public DNSSOARecord() {
            this.Initialize();
            this.ProcessResults();
        }

        public DNSSOARecord(DNSResourceRecord parentRecord) {
            parentRecord.ShallowCopy<DNSResourceRecord, DNSSOARecord>(this);
            this.ProcessResults();
        }

        public DNSSOARecord(DirectoryEntry directoryEntry, bool destroyInputObject = true)
            : base(directoryEntry, destroyInputObject) {
            if (this.GetType().Name == typeof(DNSSOARecord).Name) {
                this.Attributes = null;
            }
        }

        public DNSSOARecord(SearchResult result, bool destroyInputObject = true)
            : base(result, destroyInputObject) {
            if (this.GetType().Name == typeof(DNSSOARecord).Name) {
                this.Attributes = null;
            }
        }
        #endregion

        #region Methods
        protected override void Initialize() {
            this.ResponsiblePerson = string.Empty;
            this.TargetName = string.Empty;
        }

        internal override void ProcessDNSRecordStream(EndianBinaryReader propertyReader) {
            base.ProcessDNSRecordStream(propertyReader);

            try {
                this.Serial = propertyReader.ReadUInt32(isBigEndian: true);
                this.Refresh = propertyReader.ReadUInt32(isBigEndian: true);
                this.Retry = propertyReader.ReadUInt32(isBigEndian: true);
                this.Expire = propertyReader.ReadUInt32(isBigEndian: true);
                this.MinimumTTL = propertyReader.ReadUInt32(isBigEndian: true);
                this.TargetName = base.ReadName(propertyReader);
                this.ResponsiblePerson = base.ReadName(propertyReader);

                base.RecordData = string.Format("{0} {1} {2} {3} {4} {5} {6}",
                    this.TargetName,
                    this.ResponsiblePerson,
                    this.Serial,
                    this.Refresh,
                    this.Retry,
                    this.Expire,
                    this.MinimumTTL);
            }
            catch (Exception e) {
                Debug.WriteLine(string.Format("{0}  [ThreadID: {1}]  {2} Error: {3}", DateTime.Now.TimeOfDay, Thread.CurrentThread.ManagedThreadId, CustomExtensions.CurrentMethodName(), e.VerboseExceptionString()));
                throw;
            }
        }      

        protected override void ProcessResults() {

            try {
                if (string.IsNullOrWhiteSpace(this.DN)) {
                    base.ProcessResults();
                }

                var memoryStream = new MemoryStream(this.DNSRecord);
                using (var propertyReader = new EndianBinaryReader(memoryStream)) {
                    this.ProcessDNSRecordStream(propertyReader);
                }

                this.IsValid = !string.IsNullOrWhiteSpace(this.DN)
                    && this.ObjectClass.Any(x => x.Equals(ObjectCategoryShortName, StringComparison.OrdinalIgnoreCase))
                    && (this.RecordType == DNSRecordType.SOA);
            }
            catch (Exception e) {
                Debug.WriteLine(string.Format("{0}  [ThreadID: {1}]  {2} Error: {3}", DateTime.Now.TimeOfDay, Thread.CurrentThread.ManagedThreadId, CustomExtensions.CurrentMethodName(), e.VerboseExceptionString()));
                throw;
            }

        }
        #endregion

    }
}
